Libraries

library(ggplot2)
library(scales)
library(dplyr)
library(survival)
library(survminer)
library(lubridate)
library(tidyr)
library(stringr)
library(forcats)
library(wesanderson)
library(class)
library(rpart)
library(rpart.plot)
library(plotly)

ESL Dataset

load("../data/mixture.example.RData")
intercept = 50.0
coef_x1 = 10.0
coef_x2 = -2.0
set.seed(1000)
df <- data.frame(x1 = mixture.example$x[,1], 
                 x2 = mixture.example$x[,2]) %>%
  mutate(y = intercept + coef_x1 * x1 + coef_x2 * x2 + rnorm(length(x1), 0, 5))
x.grid <- seq(min(df$x1), max(df$x1), 0.1)
y.grid <- seq(min(df$x2), max(df$x2), 0.1)
hist(df$y)

Figure (just the dataset)

xy.grid <- expand.grid(x.grid, y.grid)
names(xy.grid) <- c("x1", "x2")
p <- ggplot(df) + 
  geom_point(aes(x = x1, y = x2, colour = y, fill = y), pch = 21) + 
  geom_point(aes(x = x1, y = x2), alpha = 0.5, data = xy.grid, colour = "gray50", size = 0.02) + 
  theme_minimal() + 
  xlab("Disease Severity Score (x1)") + 
  ylab("Social Determinants Score (x2)") + 
  theme(axis.text = element_blank()) + 
  theme(legend.position = "bottom", panel.grid.major = element_blank(), panel.grid.minor = element_blank()) + 
  scale_colour_gradient(name = "Recurrence\nBiomarker (y)", low = "#00bfc4", high = "#f8766d") + 
  scale_fill_gradient(name = "Recurrence\nBiomarker (y)", low = "#00bfc4", high = "#f8766d")
print(p)
ggsave(p, filename = "../img/esl-reg-just-data.png", height=4.5, width=4, units="in", dpi=300)

Linear regression

x.grid <- seq(min(df$x1), max(df$x1), 0.05)
y.grid <- seq(min(df$x2), max(df$x2), 0.05)
xy.grid <- expand.grid(x.grid, y.grid)
names(xy.grid) <- c("x1", "x2")
m <- lm(y ~ x1 + x2, data = df)
xy.grid$yhat <- predict(m, xy.grid)
p <- ggplot(df) + 
  geom_point(aes(x = x1, y = x2, colour = y, fill = y), pch = 21) + 
  geom_point(aes(x = x1, y = x2, colour = yhat), alpha = 0.4, data = xy.grid, size = 0.5) + 
  theme_minimal() + 
  xlab("Disease Severity Score (x1)") + 
  ylab("Social Determinants Score (x2)") + theme(axis.text = element_blank()) + 
  scale_fill_gradient(name = "Recurrence\nBiomarker (y)", low = "#00bfc4", high = "#f8766d") +
  stat_contour(aes(x = x1, y = x2, z = yhat), breaks = quantile(xy.grid$yhat, seq(0, 1, 0.25)), 
               data = xy.grid, colour = "gray30") + 
  scale_colour_gradient(name = "Recurrence\nBiomarker (y)", low = "#00bfc4", high = "#f8766d") + 
  theme(legend.position = "none", panel.grid.major = element_blank(), panel.grid.minor = element_blank()) + 
  coord_cartesian(xlim=c(min(xy.grid$x1),max(xy.grid$x1)), ylim=c(min(xy.grid$x2),max(xy.grid$x2)))
print(p)
ggsave(p, filename = "../img/esl-reg-linear.png", height=4, width=4, units="in", dpi=300)

KNN with K=15

x.grid <- seq(min(df$x1), max(df$x1), 0.05)
y.grid <- seq(min(df$x2), max(df$x2), 0.05)
xy.grid <- expand.grid(x.grid, y.grid)
names(xy.grid) <- c("x1", "x2")
m <- knn(df[,1:2], xy.grid, df[,3], k=15, prob=TRUE)
xy.grid$yhat <- as.numeric(as.character(m))
p <- ggplot(df) + 
  geom_point(aes(x = x1, y = x2, colour = y, fill = y), pch = 21) + 
  geom_point(aes(x = x1, y = x2, colour = yhat), alpha = 0.4, data = xy.grid, size = 0.5) + 
  theme_minimal() + 
  xlab("Disease Severity Score (x1)") + 
  ylab("Social Determinants Score (x2)") + theme(axis.text = element_blank()) + 
  scale_fill_gradient(name = "Recurrence\nBiomarker (y)", low = "#00bfc4", high = "#f8766d") +
  stat_contour(aes(x = x1, y = x2, z = yhat), breaks = quantile(xy.grid$yhat, seq(0, 1, 0.25)), 
               data = xy.grid, colour = "gray30") + 
  scale_colour_gradient(name = "Recurrence\nBiomarker (y)", low = "#00bfc4", high = "#f8766d") + 
  theme(legend.position = "none", panel.grid.major = element_blank(), panel.grid.minor = element_blank()) + 
  coord_cartesian(xlim=c(min(xy.grid$x1),max(xy.grid$x1)), ylim=c(min(xy.grid$x2),max(xy.grid$x2)))
print(p)
ggsave(p, filename = "../img/esl-reg-knn-15.png", height=4, width=4, units="in", dpi=300)

Decision tree

x.grid <- seq(min(df$x1), max(df$x1), 0.05)
y.grid <- seq(min(df$x2), max(df$x2), 0.05)
xy.grid <- expand.grid(x.grid, y.grid)
names(xy.grid) <- c("x1", "x2")
m <- rpart(y ~ x1 + x2, data = df)
xy.grid$yhat <- predict(m, xy.grid)
p <- ggplot(df) + 
  geom_point(aes(x = x1, y = x2, colour = y, fill = y), pch = 21) + 
  geom_point(aes(x = x1, y = x2, colour = yhat), alpha = 0.4, data = xy.grid, size = 0.5) + 
  theme_minimal() + 
  xlab("Disease Severity Score (x1)") + 
  ylab("Social Determinants Score (x2)") + theme(axis.text = element_blank()) + 
  scale_fill_gradient(name = "Recurrence\nBiomarker (y)", low = "#00bfc4", high = "#f8766d") +
  stat_contour(aes(x = x1, y = x2, z = yhat), breaks = quantile(xy.grid$yhat, seq(0, 1, 0.25)), 
               data = xy.grid, colour = "gray30") + 
  scale_colour_gradient(name = "Recurrence\nBiomarker (y)", low = "#00bfc4", high = "#f8766d") + 
  theme(legend.position = "none", panel.grid.major = element_blank(), panel.grid.minor = element_blank()) + 
  coord_cartesian(xlim=c(min(xy.grid$x1),max(xy.grid$x1)), ylim=c(min(xy.grid$x2),max(xy.grid$x2)))
print(p)
ggsave(p, filename = "../img/esl-reg-decision-tree.png", height=4, width=4, units="in", dpi=300)

Standard deviation reduction!

set.seed(200)
df <- data.frame(y = c(rnorm(100, 0, 1), rnorm(100, 3, 1)), 
                 gauss_id = c(rep(0.1, 100), rep(0.9, 100)),
                 x1 = rbinom(200, 1, 0.5)) %>%
  mutate(x2 = rbinom(length(x1), 1, gauss_id)) %>%
  gather(x1:x2, key = "variable", value = "value")

p <- ggplot(df) + 
  geom_histogram(aes(x = y, fill = as.factor(value)), position = "stack", alpha = 0.5, bins = 30) + 
  theme_bw() + scale_fill_discrete(name = "Variable Value") + 
  facet_wrap(~variable, nrow = 2) + ylab("Count") + xlab("Outcome (y)")
print(p)
ggsave(p, filename = "../img/esl-reg-decision-tree-varsplit.png", height=4, width=6, units="in", dpi=300)

LS0tCnRpdGxlOiAiUmVncmVzc2lvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgTGlicmFyaWVzCgpgYGB7ciBzZXR1cH0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShkcGx5cikKbGlicmFyeShzdXJ2aXZhbCkKbGlicmFyeShzdXJ2bWluZXIpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoZm9yY2F0cykKbGlicmFyeSh3ZXNhbmRlcnNvbikKbGlicmFyeShjbGFzcykKbGlicmFyeShycGFydCkKbGlicmFyeShycGFydC5wbG90KQpsaWJyYXJ5KHBsb3RseSkKYGBgCgojIyBFU0wgRGF0YXNldAoKYGBge3J9CmxvYWQoIi4uL2RhdGEvbWl4dHVyZS5leGFtcGxlLlJEYXRhIikKaW50ZXJjZXB0ID0gNTAuMApjb2VmX3gxID0gMTAuMApjb2VmX3gyID0gLTIuMApzZXQuc2VlZCgxMDAwKQpkZiA8LSBkYXRhLmZyYW1lKHgxID0gbWl4dHVyZS5leGFtcGxlJHhbLDFdLCAKICAgICAgICAgICAgICAgICB4MiA9IG1peHR1cmUuZXhhbXBsZSR4WywyXSkgJT4lCiAgbXV0YXRlKHkgPSBpbnRlcmNlcHQgKyBjb2VmX3gxICogeDEgKyBjb2VmX3gyICogeDIgKyBybm9ybShsZW5ndGgoeDEpLCAwLCA1KSkKeC5ncmlkIDwtIHNlcShtaW4oZGYkeDEpLCBtYXgoZGYkeDEpLCAwLjEpCnkuZ3JpZCA8LSBzZXEobWluKGRmJHgyKSwgbWF4KGRmJHgyKSwgMC4xKQpoaXN0KGRmJHkpCmBgYAoKRmlndXJlIChqdXN0IHRoZSBkYXRhc2V0KQoKYGBge3J9Cnh5LmdyaWQgPC0gZXhwYW5kLmdyaWQoeC5ncmlkLCB5LmdyaWQpCm5hbWVzKHh5LmdyaWQpIDwtIGMoIngxIiwgIngyIikKcCA8LSBnZ3Bsb3QoZGYpICsgCiAgZ2VvbV9wb2ludChhZXMoeCA9IHgxLCB5ID0geDIsIGNvbG91ciA9IHksIGZpbGwgPSB5KSwgcGNoID0gMjEpICsgCiAgZ2VvbV9wb2ludChhZXMoeCA9IHgxLCB5ID0geDIpLCBhbHBoYSA9IDAuNSwgZGF0YSA9IHh5LmdyaWQsIGNvbG91ciA9ICJncmF5NTAiLCBzaXplID0gMC4wMikgKyAKICB0aGVtZV9taW5pbWFsKCkgKyAKICB4bGFiKCJEaXNlYXNlIFNldmVyaXR5IFNjb3JlICh4MSkiKSArIAogIHlsYWIoIlNvY2lhbCBEZXRlcm1pbmFudHMgU2NvcmUgKHgyKSIpICsgCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKSArIAogIHNjYWxlX2NvbG91cl9ncmFkaWVudChuYW1lID0gIlJlY3VycmVuY2VcbkJpb21hcmtlciAoeSkiLCBsb3cgPSAiIzAwYmZjNCIsIGhpZ2ggPSAiI2Y4NzY2ZCIpICsgCiAgc2NhbGVfZmlsbF9ncmFkaWVudChuYW1lID0gIlJlY3VycmVuY2VcbkJpb21hcmtlciAoeSkiLCBsb3cgPSAiIzAwYmZjNCIsIGhpZ2ggPSAiI2Y4NzY2ZCIpCnByaW50KHApCmdnc2F2ZShwLCBmaWxlbmFtZSA9ICIuLi9pbWcvZXNsLXJlZy1qdXN0LWRhdGEucG5nIiwgaGVpZ2h0PTQuNSwgd2lkdGg9NCwgdW5pdHM9ImluIiwgZHBpPTMwMCkKYGBgCgpMaW5lYXIgcmVncmVzc2lvbgoKYGBge3J9CnguZ3JpZCA8LSBzZXEobWluKGRmJHgxKSwgbWF4KGRmJHgxKSwgMC4wNSkKeS5ncmlkIDwtIHNlcShtaW4oZGYkeDIpLCBtYXgoZGYkeDIpLCAwLjA1KQp4eS5ncmlkIDwtIGV4cGFuZC5ncmlkKHguZ3JpZCwgeS5ncmlkKQpuYW1lcyh4eS5ncmlkKSA8LSBjKCJ4MSIsICJ4MiIpCm0gPC0gbG0oeSB+IHgxICsgeDIsIGRhdGEgPSBkZikKeHkuZ3JpZCR5aGF0IDwtIHByZWRpY3QobSwgeHkuZ3JpZCkKcCA8LSBnZ3Bsb3QoZGYpICsgCiAgZ2VvbV9wb2ludChhZXMoeCA9IHgxLCB5ID0geDIsIGNvbG91ciA9IHksIGZpbGwgPSB5KSwgcGNoID0gMjEpICsgCiAgZ2VvbV9wb2ludChhZXMoeCA9IHgxLCB5ID0geDIsIGNvbG91ciA9IHloYXQpLCBhbHBoYSA9IDAuNCwgZGF0YSA9IHh5LmdyaWQsIHNpemUgPSAwLjUpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgeGxhYigiRGlzZWFzZSBTZXZlcml0eSBTY29yZSAoeDEpIikgKyAKICB5bGFiKCJTb2NpYWwgRGV0ZXJtaW5hbnRzIFNjb3JlICh4MikiKSArIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50KG5hbWUgPSAiUmVjdXJyZW5jZVxuQmlvbWFya2VyICh5KSIsIGxvdyA9ICIjMDBiZmM0IiwgaGlnaCA9ICIjZjg3NjZkIikgKwogIHN0YXRfY29udG91cihhZXMoeCA9IHgxLCB5ID0geDIsIHogPSB5aGF0KSwgYnJlYWtzID0gcXVhbnRpbGUoeHkuZ3JpZCR5aGF0LCBzZXEoMCwgMSwgMC4yNSkpLCAKICAgICAgICAgICAgICAgZGF0YSA9IHh5LmdyaWQsIGNvbG91ciA9ICJncmF5MzAiKSArIAogIHNjYWxlX2NvbG91cl9ncmFkaWVudChuYW1lID0gIlJlY3VycmVuY2VcbkJpb21hcmtlciAoeSkiLCBsb3cgPSAiIzAwYmZjNCIsIGhpZ2ggPSAiI2Y4NzY2ZCIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKSArIAogIGNvb3JkX2NhcnRlc2lhbih4bGltPWMobWluKHh5LmdyaWQkeDEpLG1heCh4eS5ncmlkJHgxKSksIHlsaW09YyhtaW4oeHkuZ3JpZCR4MiksbWF4KHh5LmdyaWQkeDIpKSkKcHJpbnQocCkKZ2dzYXZlKHAsIGZpbGVuYW1lID0gIi4uL2ltZy9lc2wtcmVnLWxpbmVhci5wbmciLCBoZWlnaHQ9NCwgd2lkdGg9NCwgdW5pdHM9ImluIiwgZHBpPTMwMCkKYGBgCgpLTk4gd2l0aCBLPTE1CgpgYGB7cn0KeC5ncmlkIDwtIHNlcShtaW4oZGYkeDEpLCBtYXgoZGYkeDEpLCAwLjA1KQp5LmdyaWQgPC0gc2VxKG1pbihkZiR4MiksIG1heChkZiR4MiksIDAuMDUpCnh5LmdyaWQgPC0gZXhwYW5kLmdyaWQoeC5ncmlkLCB5LmdyaWQpCm5hbWVzKHh5LmdyaWQpIDwtIGMoIngxIiwgIngyIikKbSA8LSBrbm4oZGZbLDE6Ml0sIHh5LmdyaWQsIGRmWywzXSwgaz0xNSwgcHJvYj1UUlVFKQp4eS5ncmlkJHloYXQgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIobSkpCnAgPC0gZ2dwbG90KGRmKSArIAogIGdlb21fcG9pbnQoYWVzKHggPSB4MSwgeSA9IHgyLCBjb2xvdXIgPSB5LCBmaWxsID0geSksIHBjaCA9IDIxKSArIAogIGdlb21fcG9pbnQoYWVzKHggPSB4MSwgeSA9IHgyLCBjb2xvdXIgPSB5aGF0KSwgYWxwaGEgPSAwLjQsIGRhdGEgPSB4eS5ncmlkLCBzaXplID0gMC41KSArIAogIHRoZW1lX21pbmltYWwoKSArIAogIHhsYWIoIkRpc2Vhc2UgU2V2ZXJpdHkgU2NvcmUgKHgxKSIpICsgCiAgeWxhYigiU29jaWFsIERldGVybWluYW50cyBTY29yZSAoeDIpIikgKyB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgc2NhbGVfZmlsbF9ncmFkaWVudChuYW1lID0gIlJlY3VycmVuY2VcbkJpb21hcmtlciAoeSkiLCBsb3cgPSAiIzAwYmZjNCIsIGhpZ2ggPSAiI2Y4NzY2ZCIpICsKICBzdGF0X2NvbnRvdXIoYWVzKHggPSB4MSwgeSA9IHgyLCB6ID0geWhhdCksIGJyZWFrcyA9IHF1YW50aWxlKHh5LmdyaWQkeWhhdCwgc2VxKDAsIDEsIDAuMjUpKSwgCiAgICAgICAgICAgICAgIGRhdGEgPSB4eS5ncmlkLCBjb2xvdXIgPSAiZ3JheTMwIikgKyAKICBzY2FsZV9jb2xvdXJfZ3JhZGllbnQobmFtZSA9ICJSZWN1cnJlbmNlXG5CaW9tYXJrZXIgKHkpIiwgbG93ID0gIiMwMGJmYzQiLCBoaWdoID0gIiNmODc2NmQiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKG1pbih4eS5ncmlkJHgxKSxtYXgoeHkuZ3JpZCR4MSkpLCB5bGltPWMobWluKHh5LmdyaWQkeDIpLG1heCh4eS5ncmlkJHgyKSkpCnByaW50KHApCmdnc2F2ZShwLCBmaWxlbmFtZSA9ICIuLi9pbWcvZXNsLXJlZy1rbm4tMTUucG5nIiwgaGVpZ2h0PTQsIHdpZHRoPTQsIHVuaXRzPSJpbiIsIGRwaT0zMDApCmBgYAoKRGVjaXNpb24gdHJlZQoKYGBge3J9CnguZ3JpZCA8LSBzZXEobWluKGRmJHgxKSwgbWF4KGRmJHgxKSwgMC4wNSkKeS5ncmlkIDwtIHNlcShtaW4oZGYkeDIpLCBtYXgoZGYkeDIpLCAwLjA1KQp4eS5ncmlkIDwtIGV4cGFuZC5ncmlkKHguZ3JpZCwgeS5ncmlkKQpuYW1lcyh4eS5ncmlkKSA8LSBjKCJ4MSIsICJ4MiIpCm0gPC0gcnBhcnQoeSB+IHgxICsgeDIsIGRhdGEgPSBkZikKeHkuZ3JpZCR5aGF0IDwtIHByZWRpY3QobSwgeHkuZ3JpZCkKcCA8LSBnZ3Bsb3QoZGYpICsgCiAgZ2VvbV9wb2ludChhZXMoeCA9IHgxLCB5ID0geDIsIGNvbG91ciA9IHksIGZpbGwgPSB5KSwgcGNoID0gMjEpICsgCiAgZ2VvbV9wb2ludChhZXMoeCA9IHgxLCB5ID0geDIsIGNvbG91ciA9IHloYXQpLCBhbHBoYSA9IDAuNCwgZGF0YSA9IHh5LmdyaWQsIHNpemUgPSAwLjUpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgeGxhYigiRGlzZWFzZSBTZXZlcml0eSBTY29yZSAoeDEpIikgKyAKICB5bGFiKCJTb2NpYWwgRGV0ZXJtaW5hbnRzIFNjb3JlICh4MikiKSArIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50KG5hbWUgPSAiUmVjdXJyZW5jZVxuQmlvbWFya2VyICh5KSIsIGxvdyA9ICIjMDBiZmM0IiwgaGlnaCA9ICIjZjg3NjZkIikgKwogIHN0YXRfY29udG91cihhZXMoeCA9IHgxLCB5ID0geDIsIHogPSB5aGF0KSwgYnJlYWtzID0gcXVhbnRpbGUoeHkuZ3JpZCR5aGF0LCBzZXEoMCwgMSwgMC4yNSkpLCAKICAgICAgICAgICAgICAgZGF0YSA9IHh5LmdyaWQsIGNvbG91ciA9ICJncmF5MzAiKSArIAogIHNjYWxlX2NvbG91cl9ncmFkaWVudChuYW1lID0gIlJlY3VycmVuY2VcbkJpb21hcmtlciAoeSkiLCBsb3cgPSAiIzAwYmZjNCIsIGhpZ2ggPSAiI2Y4NzY2ZCIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKSArIAogIGNvb3JkX2NhcnRlc2lhbih4bGltPWMobWluKHh5LmdyaWQkeDEpLG1heCh4eS5ncmlkJHgxKSksIHlsaW09YyhtaW4oeHkuZ3JpZCR4MiksbWF4KHh5LmdyaWQkeDIpKSkKcHJpbnQocCkKZ2dzYXZlKHAsIGZpbGVuYW1lID0gIi4uL2ltZy9lc2wtcmVnLWRlY2lzaW9uLXRyZWUucG5nIiwgaGVpZ2h0PTQsIHdpZHRoPTQsIHVuaXRzPSJpbiIsIGRwaT0zMDApCmBgYAoKU3RhbmRhcmQgZGV2aWF0aW9uIHJlZHVjdGlvbiEKCmBgYHtyfQpzZXQuc2VlZCgyMDApCmRmIDwtIGRhdGEuZnJhbWUoeSA9IGMocm5vcm0oMTAwLCAwLCAxKSwgcm5vcm0oMTAwLCAzLCAxKSksIAogICAgICAgICAgICAgICAgIGdhdXNzX2lkID0gYyhyZXAoMC4xLCAxMDApLCByZXAoMC45LCAxMDApKSwKICAgICAgICAgICAgICAgICB4MSA9IHJiaW5vbSgyMDAsIDEsIDAuNSkpICU+JQogIG11dGF0ZSh4MiA9IHJiaW5vbShsZW5ndGgoeDEpLCAxLCBnYXVzc19pZCkpICU+JQogIGdhdGhlcih4MTp4Miwga2V5ID0gInZhcmlhYmxlIiwgdmFsdWUgPSAidmFsdWUiKQoKcCA8LSBnZ3Bsb3QoZGYpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSB5LCBmaWxsID0gYXMuZmFjdG9yKHZhbHVlKSksIHBvc2l0aW9uID0gInN0YWNrIiwgYWxwaGEgPSAwLjUsIGJpbnMgPSAzMCkgKyAKICB0aGVtZV9idygpICsgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIlZhcmlhYmxlIFZhbHVlIikgKyAKICBmYWNldF93cmFwKH52YXJpYWJsZSwgbnJvdyA9IDIpICsgeWxhYigiQ291bnQiKSArIHhsYWIoIk91dGNvbWUgKHkpIikKcHJpbnQocCkKZ2dzYXZlKHAsIGZpbGVuYW1lID0gIi4uL2ltZy9lc2wtcmVnLWRlY2lzaW9uLXRyZWUtdmFyc3BsaXQucG5nIiwgaGVpZ2h0PTQsIHdpZHRoPTYsIHVuaXRzPSJpbiIsIGRwaT0zMDApCmBgYAoKCg==